// source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/RouteModel.js?ver=2.9.1 function CMMRM_RouteModel(data, waypointsString, locations) { // console.log(data); // console.log('waypointsString', waypointsString); this.data = data; this.waypointsString = (typeof waypointsString == 'string' ? waypointsString : ''); this.waypointsCoords = []; this.waypoints = []; this.decodeWaypoints(); this.locations = []; this.addLocations(locations); } CMMRM_RouteModel.prototype.addLocations = function(locations) { for (var i=0; i https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/RequestTrail.js?ver=2.9.1 function CMMRM_RequestTrail(travelMode, waypointsCoords) { this.travelMode = travelMode; this.waypointsCoords = waypointsCoords; this.response = null; this.status = null; } CMMRM_RequestTrail.prototype.run = function(mapRenderer, callback) { if ('DIRECT' == this.travelMode) { this.requestTrailDirect(mapRenderer, callback); } else { this.requestTrailGoogle(callback); } }; CMMRM_RequestTrail.prototype.getDistance = function() { var totalDistance = 0; var legs = this.response.routes[0].legs; for (var i=0; i 0) { leg.steps[0].path.push(coord); leg.steps[0].distance = {text: distance.toString(), value: distance}; if (coords.length < CMMRM_Map_Settings.editorWaypointsLimit) { // Created new legs only if it's simple trail to avoid too many legs for the imported GPX files legs.push(leg); } } if (coords.length < CMMRM_Map_Settings.editorWaypointsLimit) { // Created new legs only if it's simple trail to avoid too many legs for the imported GPX files leg = jQuery.extend(true, {}, newLeg); // commented to avoid too many legs for imported files } leg.steps[0].path.push(coord); lastCoord = coord; } legs.push(leg); // added to create only one leg for direct travel mode this.status = google.maps.DirectionsStatus.OK; this.response = { routes: [{ overview_path: overview_path, overview_polyline: google.maps.geometry.encoding.encodePath(overview_path), legs: legs }] }; callback(this.response, this.status); // this.requestTrailCallback('DIRECT', response, status); }; CMMRM_RequestTrail.prototype.getPathCoords = function() { var result = []; var legs = this.response.routes[0].legs; for (var legIndex=0; legIndex 0) { return this.response.routes[0].overview_path; } else { return ''; } }; CMMRM_RequestTrail.prototype.getOverviewPolyline = function() { if (typeof this.response.routes == 'object' && this.response.routes.length > 0) { return this.response.routes[0].overview_polyline; } else { return ''; } }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/markerclusterer.js?ver=2.9.1 /** * @name MarkerClusterer for Google Maps v3 * @version version 1.0.1 * @author Luke Mahe * @fileoverview * The library creates and manages per-zoom-level clusters for large amounts of * markers. *
* This is a v3 implementation of the * v2 MarkerClusterer. */ /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A Marker Clusterer that clusters markers. * * @param {google.maps.Map} map The Google map to attach to. * @param {Array.=} opt_markers Optional markers to add to * the cluster. * @param {Object=} opt_options support the following options: * 'gridSize': (number) The grid size of a cluster in pixels. * 'maxZoom': (number) The maximum zoom level that a marker can be part of a * cluster. * 'zoomOnClick': (boolean) Whether the default behaviour of clicking on a * cluster is to zoom into it. * 'averageCenter': (boolean) Whether the center of each cluster should be * the average of all markers in the cluster. * 'minimumClusterSize': (number) The minimum number of markers to be in a * cluster before the markers are hidden and a count * is shown. * 'styles': (object) An object that has style properties: * 'url': (string) The image url. * 'height': (number) The image height. * 'width': (number) The image width. * 'anchor': (Array) The anchor position of the label text. * 'textColor': (string) The text color. * 'textSize': (number) The text size. * 'backgroundPosition': (string) The position of the backgound x, y. * @constructor * @extends google.maps.OverlayView */ function MarkerClusterer(map, opt_markers, opt_options) { // MarkerClusterer implements google.maps.OverlayView interface. We use the // extend function to extend MarkerClusterer with google.maps.OverlayView // because it might not always be available when the code is defined so we // look for it at the last possible moment. If it doesn't exist now then // there is no point going ahead :) this.extend(MarkerClusterer, google.maps.OverlayView); this.map_ = map; /** * @type {Array.} * @private */ this.markers_ = []; /** * @type {Array.} */ this.clusters_ = []; this.sizes = [53, 56, 66, 78, 90]; /** * @private */ this.styles_ = []; /** * @type {boolean} * @private */ this.ready_ = false; var options = opt_options || {}; /** * @type {number} * @private */ this.gridSize_ = options['gridSize'] || 60; /** * @private */ this.minClusterSize_ = options['minimumClusterSize'] || 2; /** * @type {?number} * @private */ this.maxZoom_ = options['maxZoom'] || null; this.styles_ = options['styles'] || []; /** * @type {string} * @private */ this.imagePath_ = options['imagePath'] || this.MARKER_CLUSTER_IMAGE_PATH_; /** * @type {string} * @private */ this.imageExtension_ = options['imageExtension'] || this.MARKER_CLUSTER_IMAGE_EXTENSION_; /** * @type {boolean} * @private */ this.zoomOnClick_ = true; if (options['zoomOnClick'] != undefined) { this.zoomOnClick_ = options['zoomOnClick']; } /** * @type {boolean} * @private */ this.averageCenter_ = false; if (options['averageCenter'] != undefined) { this.averageCenter_ = options['averageCenter']; } this.setupStyles_(); this.setMap(map); /** * @type {number} * @private */ this.prevZoom_ = this.map_.getZoom(); // Add the map event listeners var that = this; google.maps.event.addListener(this.map_, 'zoom_changed', function() { // Determines map type and prevent illegal zoom levels var zoom = that.map_.getZoom(); var minZoom = that.map_.minZoom || 0; var maxZoom = Math.min(that.map_.maxZoom || 100, that.map_.mapTypes[that.map_.getMapTypeId()] ? that.map_.mapTypes[that.map_.getMapTypeId()].maxZoom : 999); zoom = Math.min(Math.max(zoom,minZoom),maxZoom); if (that.prevZoom_ != zoom) { that.prevZoom_ = zoom; that.resetViewport(); } }); google.maps.event.addListener(this.map_, 'idle', function() { that.redraw(); }); // Finally, add the markers if (opt_markers && (opt_markers.length || Object.keys(opt_markers).length)) { this.addMarkers(opt_markers, false); } } /** * The marker cluster image path. * * @type {string} * @private */ MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = '../images/m'; /** * The marker cluster image path. * * @type {string} * @private */ MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png'; /** * Extends a objects prototype by anothers. * * @param {Object} obj1 The object to be extended. * @param {Object} obj2 The object to extend with. * @return {Object} The new extended object. * @ignore */ MarkerClusterer.prototype.extend = function(obj1, obj2) { return (function(object) { for (var property in object.prototype) { this.prototype[property] = object.prototype[property]; } return this; }).apply(obj1, [obj2]); }; /** * Implementaion of the interface method. * @ignore */ MarkerClusterer.prototype.onAdd = function() { this.setReady_(true); }; /** * Implementaion of the interface method. * @ignore */ MarkerClusterer.prototype.draw = function() {}; /** * Sets up the styles object. * * @private */ MarkerClusterer.prototype.setupStyles_ = function() { if (this.styles_.length) { return; } for (var i = 0, size; size = this.sizes[i]; i++) { this.styles_.push({ url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_, height: size, width: size }); } }; /** * Fit the map to the bounds of the markers in the clusterer. */ MarkerClusterer.prototype.fitMapToMarkers = function() { var markers = this.getMarkers(); var bounds = new google.maps.LatLngBounds(); for (var i = 0, marker; marker = markers[i]; i++) { bounds.extend(marker.getPosition()); } this.map_.fitBounds(bounds); }; /** * Sets the styles. * * @param {Object} styles The style to set. */ MarkerClusterer.prototype.setStyles = function(styles) { this.styles_ = styles; }; /** * Gets the styles. * * @return {Object} The styles object. */ MarkerClusterer.prototype.getStyles = function() { return this.styles_; }; /** * Whether zoom on click is set. * * @return {boolean} True if zoomOnClick_ is set. */ MarkerClusterer.prototype.isZoomOnClick = function() { return this.zoomOnClick_; }; /** * Whether average center is set. * * @return {boolean} True if averageCenter_ is set. */ MarkerClusterer.prototype.isAverageCenter = function() { return this.averageCenter_; }; /** * Returns the array of markers in the clusterer. * * @return {Array.} The markers. */ MarkerClusterer.prototype.getMarkers = function() { return this.markers_; }; /** * Returns the number of markers in the clusterer * * @return {Number} The number of markers. */ MarkerClusterer.prototype.getTotalMarkers = function() { return this.markers_.length; }; /** * Sets the max zoom for the clusterer. * * @param {number} maxZoom The max zoom level. */ MarkerClusterer.prototype.setMaxZoom = function(maxZoom) { this.maxZoom_ = maxZoom; }; /** * Gets the max zoom for the clusterer. * * @return {number} The max zoom level. */ MarkerClusterer.prototype.getMaxZoom = function() { return this.maxZoom_; }; /** * The function for calculating the cluster icon image. * * @param {Array.} markers The markers in the clusterer. * @param {number} numStyles The number of styles available. * @return {Object} A object properties: 'text' (string) and 'index' (number). * @private */ MarkerClusterer.prototype.calculator_ = function(markers, numStyles) { var index = 0; var count = markers.length; var dv = count; while (dv !== 0) { dv = parseInt(dv / 10, 10); index++; } index = Math.min(index, numStyles); return { text: count, index: index }; }; /** * Set the calculator function. * * @param {function(Array, number)} calculator The function to set as the * calculator. The function should return a object properties: * 'text' (string) and 'index' (number). * */ MarkerClusterer.prototype.setCalculator = function(calculator) { this.calculator_ = calculator; }; /** * Get the calculator function. * * @return {function(Array, number)} the calculator function. */ MarkerClusterer.prototype.getCalculator = function() { return this.calculator_; }; /** * Add an array of markers to the clusterer. * * @param {Array.} markers The markers to add. * @param {boolean=} opt_nodraw Whether to redraw the clusters. */ MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) { if (markers.length) { for (var i = 0, marker; marker = markers[i]; i++) { this.pushMarkerTo_(marker); } } else if (Object.keys(markers).length) { for (var marker in markers) { this.pushMarkerTo_(markers[marker]); } } if (!opt_nodraw) { this.redraw(); } }; /** * Pushes a marker to the clusterer. * * @param {google.maps.Marker} marker The marker to add. * @private */ MarkerClusterer.prototype.pushMarkerTo_ = function(marker) { marker.isAdded = false; if (marker['draggable']) { // If the marker is draggable add a listener so we update the clusters on // the drag end. var that = this; google.maps.event.addListener(marker, 'dragend', function() { marker.isAdded = false; that.repaint(); }); } this.markers_.push(marker); }; /** * Adds a marker to the clusterer and redraws if needed. * * @param {google.maps.Marker} marker The marker to add. * @param {boolean=} opt_nodraw Whether to redraw the clusters. */ MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) { this.pushMarkerTo_(marker); if (!opt_nodraw) { this.redraw(); } }; /** * Removes a marker and returns true if removed, false if not * * @param {google.maps.Marker} marker The marker to remove * @return {boolean} Whether the marker was removed or not * @private */ MarkerClusterer.prototype.removeMarker_ = function(marker) { var index = -1; if (this.markers_.indexOf) { index = this.markers_.indexOf(marker); } else { for (var i = 0, m; m = this.markers_[i]; i++) { if (m == marker) { index = i; break; } } } if (index == -1) { // Marker is not in our list of markers. return false; } marker.setMap(null); this.markers_.splice(index, 1); return true; }; /** * Remove a marker from the cluster. * * @param {google.maps.Marker} marker The marker to remove. * @param {boolean=} opt_nodraw Optional boolean to force no redraw. * @return {boolean} True if the marker was removed. */ MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) { var removed = this.removeMarker_(marker); if (!opt_nodraw && removed) { this.resetViewport(); this.redraw(); return true; } else { return false; } }; /** * Removes an array of markers from the cluster. * * @param {Array.} markers The markers to remove. * @param {boolean=} opt_nodraw Optional boolean to force no redraw. */ MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) { var removed = false; for (var i = 0, marker; marker = markers[i]; i++) { var r = this.removeMarker_(marker); removed = removed || r; } if (!opt_nodraw && removed) { this.resetViewport(); this.redraw(); return true; } }; /** * Sets the clusterer's ready state. * * @param {boolean} ready The state. * @private */ MarkerClusterer.prototype.setReady_ = function(ready) { if (!this.ready_) { this.ready_ = ready; this.createClusters_(); } }; /** * Returns the number of clusters in the clusterer. * * @return {number} The number of clusters. */ MarkerClusterer.prototype.getTotalClusters = function() { return this.clusters_.length; }; /** * Returns the google map that the clusterer is associated with. * * @return {google.maps.Map} The map. */ MarkerClusterer.prototype.getMap = function() { return this.map_; }; /** * Sets the google map that the clusterer is associated with. * * @param {google.maps.Map} map The map. */ MarkerClusterer.prototype.setMap = function(map) { this.map_ = map; }; /** * Returns the size of the grid. * * @return {number} The grid size. */ MarkerClusterer.prototype.getGridSize = function() { return this.gridSize_; }; /** * Sets the size of the grid. * * @param {number} size The grid size. */ MarkerClusterer.prototype.setGridSize = function(size) { this.gridSize_ = size; }; /** * Returns the min cluster size. * * @return {number} The grid size. */ MarkerClusterer.prototype.getMinClusterSize = function() { return this.minClusterSize_; }; /** * Sets the min cluster size. * * @param {number} size The grid size. */ MarkerClusterer.prototype.setMinClusterSize = function(size) { this.minClusterSize_ = size; }; /** * Extends a bounds object by the grid size. * * @param {google.maps.LatLngBounds} bounds The bounds to extend. * @return {google.maps.LatLngBounds} The extended bounds. */ MarkerClusterer.prototype.getExtendedBounds = function(bounds) { var projection = this.getProjection(); // Turn the bounds into latlng. var tr = new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()); var bl = new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng()); // Convert the points to pixels and the extend out by the grid size. var trPix = projection.fromLatLngToDivPixel(tr); trPix.x += this.gridSize_; trPix.y -= this.gridSize_; var blPix = projection.fromLatLngToDivPixel(bl); blPix.x -= this.gridSize_; blPix.y += this.gridSize_; // Convert the pixel points back to LatLng var ne = projection.fromDivPixelToLatLng(trPix); var sw = projection.fromDivPixelToLatLng(blPix); // Extend the bounds to contain the new bounds. bounds.extend(ne); bounds.extend(sw); return bounds; }; /** * Determins if a marker is contained in a bounds. * * @param {google.maps.Marker} marker The marker to check. * @param {google.maps.LatLngBounds} bounds The bounds to check against. * @return {boolean} True if the marker is in the bounds. * @private */ MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) { return bounds.contains(marker.getPosition()); }; /** * Clears all clusters and markers from the clusterer. */ MarkerClusterer.prototype.clearMarkers = function() { this.resetViewport(true); // Set the markers a empty array. this.markers_ = []; }; /** * Clears all existing clusters and recreates them. * @param {boolean} opt_hide To also hide the marker. */ MarkerClusterer.prototype.resetViewport = function(opt_hide) { // Remove all the clusters for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { cluster.remove(); } // Reset the markers to not be added and to be invisible. for (var i = 0, marker; marker = this.markers_[i]; i++) { marker.isAdded = false; if (opt_hide) { marker.setMap(null); } } this.clusters_ = []; }; /** * */ MarkerClusterer.prototype.repaint = function() { var oldClusters = this.clusters_.slice(); this.clusters_.length = 0; this.resetViewport(); this.redraw(); // Remove the old clusters. // Do it in a timeout so the other clusters have been drawn first. window.setTimeout(function() { for (var i = 0, cluster; cluster = oldClusters[i]; i++) { cluster.remove(); } }, 0); }; /** * Redraws the clusters. */ MarkerClusterer.prototype.redraw = function() { this.createClusters_(); }; /** * Calculates the distance between two latlng locations in km. * @see http://www.movable-type.co.uk/scripts/latlong.html * * @param {google.maps.LatLng} p1 The first lat lng point. * @param {google.maps.LatLng} p2 The second lat lng point. * @return {number} The distance between the two points in km. * @private */ MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) { if (!p1 || !p2) { return 0; } var R = 6371; // Radius of the Earth in km var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var d = R * c; return d; }; /** * Add a marker to a cluster, or creates a new cluster. * * @param {google.maps.Marker} marker The marker to add. * @private */ MarkerClusterer.prototype.addToClosestCluster_ = function(marker) { var distance = 40000; // Some large number var clusterToAddTo = null; var pos = marker.getPosition(); for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { var center = cluster.getCenter(); if (center) { var d = this.distanceBetweenPoints_(center, marker.getPosition()); if (d < distance) { distance = d; clusterToAddTo = cluster; } } } if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) { clusterToAddTo.addMarker(marker); } else { var cluster = new Cluster(this); cluster.addMarker(marker); this.clusters_.push(cluster); } }; /** * Creates the clusters. * * @private */ MarkerClusterer.prototype.createClusters_ = function() { if (!this.ready_) { return; } // Get our current map view bounds. // Create a new bounds object so we don't affect the map. var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(), this.map_.getBounds().getNorthEast()); var bounds = this.getExtendedBounds(mapBounds); for (var i = 0, marker; marker = this.markers_[i]; i++) { if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) { this.addToClosestCluster_(marker); } } }; /** * A cluster that contains markers. * * @param {MarkerClusterer} markerClusterer The markerclusterer that this * cluster is associated with. * @constructor * @ignore */ function Cluster(markerClusterer) { this.markerClusterer_ = markerClusterer; this.map_ = markerClusterer.getMap(); this.gridSize_ = markerClusterer.getGridSize(); this.minClusterSize_ = markerClusterer.getMinClusterSize(); this.averageCenter_ = markerClusterer.isAverageCenter(); this.center_ = null; this.markers_ = []; this.bounds_ = null; this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(), markerClusterer.getGridSize()); } /** * Determins if a marker is already added to the cluster. * * @param {google.maps.Marker} marker The marker to check. * @return {boolean} True if the marker is already added. */ Cluster.prototype.isMarkerAlreadyAdded = function(marker) { if (this.markers_.indexOf) { return this.markers_.indexOf(marker) != -1; } else { for (var i = 0, m; m = this.markers_[i]; i++) { if (m == marker) { return true; } } } return false; }; /** * Add a marker the cluster. * * @param {google.maps.Marker} marker The marker to add. * @return {boolean} True if the marker was added. */ Cluster.prototype.addMarker = function(marker) { if (this.isMarkerAlreadyAdded(marker)) { return false; } if (!this.center_) { this.center_ = marker.getPosition(); this.calculateBounds_(); } else { if (this.averageCenter_) { var l = this.markers_.length + 1; var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l; var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l; this.center_ = new google.maps.LatLng(lat, lng); this.calculateBounds_(); } } marker.isAdded = true; this.markers_.push(marker); var len = this.markers_.length; if (len < this.minClusterSize_ && marker.getMap() != this.map_) { // Min cluster size not reached so show the marker. marker.setMap(this.map_); } if (len == this.minClusterSize_) { // Hide the markers that were showing. for (var i = 0; i < len; i++) { this.markers_[i].setMap(null); } } if (len >= this.minClusterSize_) { marker.setMap(null); } this.updateIcon(); return true; }; /** * Returns the marker clusterer that the cluster is associated with. * * @return {MarkerClusterer} The associated marker clusterer. */ Cluster.prototype.getMarkerClusterer = function() { return this.markerClusterer_; }; /** * Returns the bounds of the cluster. * * @return {google.maps.LatLngBounds} the cluster bounds. */ Cluster.prototype.getBounds = function() { var bounds = new google.maps.LatLngBounds(this.center_, this.center_); var markers = this.getMarkers(); for (var i = 0, marker; marker = markers[i]; i++) { bounds.extend(marker.getPosition()); } return bounds; }; /** * Removes the cluster */ Cluster.prototype.remove = function() { this.clusterIcon_.remove(); this.markers_.length = 0; delete this.markers_; }; /** * Returns the center of the cluster. * * @return {number} The cluster center. */ Cluster.prototype.getSize = function() { return this.markers_.length; }; /** * Returns the center of the cluster. * * @return {Array.} The cluster center. */ Cluster.prototype.getMarkers = function() { return this.markers_; }; /** * Returns the center of the cluster. * * @return {google.maps.LatLng} The cluster center. */ Cluster.prototype.getCenter = function() { return this.center_; }; /** * Calculated the extended bounds of the cluster with the grid. * * @private */ Cluster.prototype.calculateBounds_ = function() { var bounds = new google.maps.LatLngBounds(this.center_, this.center_); this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds); }; /** * Determines if a marker lies in the clusters bounds. * * @param {google.maps.Marker} marker The marker to check. * @return {boolean} True if the marker lies in the bounds. */ Cluster.prototype.isMarkerInClusterBounds = function(marker) { return this.bounds_.contains(marker.getPosition()); }; /** * Returns the map that the cluster is associated with. * * @return {google.maps.Map} The map. */ Cluster.prototype.getMap = function() { return this.map_; }; /** * Updates the cluster icon */ Cluster.prototype.updateIcon = function() { var zoom = this.map_.getZoom(); var mz = this.markerClusterer_.getMaxZoom(); if (mz && zoom > mz) { // The zoom is greater than our max zoom so show all the markers in cluster. for (var i = 0, marker; marker = this.markers_[i]; i++) { marker.setMap(this.map_); } return; } if (this.markers_.length < this.minClusterSize_) { // Min cluster size not yet reached. this.clusterIcon_.hide(); return; } var numStyles = this.markerClusterer_.getStyles().length; var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles); this.clusterIcon_.setCenter(this.center_); this.clusterIcon_.setSums(sums); this.clusterIcon_.show(); }; /** * A cluster icon * * @param {Cluster} cluster The cluster to be associated with. * @param {Object} styles An object that has style properties: * 'url': (string) The image url. * 'height': (number) The image height. * 'width': (number) The image width. * 'anchor': (Array) The anchor position of the label text. * 'textColor': (string) The text color. * 'textSize': (number) The text size. * 'backgroundPosition: (string) The background postition x, y. * @param {number=} opt_padding Optional padding to apply to the cluster icon. * @constructor * @extends google.maps.OverlayView * @ignore */ function ClusterIcon(cluster, styles, opt_padding) { cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); this.styles_ = styles; this.padding_ = opt_padding || 0; this.cluster_ = cluster; this.center_ = null; this.map_ = cluster.getMap(); this.div_ = null; this.sums_ = null; this.visible_ = false; this.setMap(this.map_); } /** * Triggers the clusterclick event and zoom's if the option is set. */ ClusterIcon.prototype.triggerClusterClick = function() { var markerClusterer = this.cluster_.getMarkerClusterer(); // Trigger the clusterclick event. google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_); if (markerClusterer.isZoomOnClick()) { // Zoom into the cluster. this.map_.fitBounds(this.cluster_.getBounds()); } }; /** * Adding the cluster icon to the dom. * @ignore */ ClusterIcon.prototype.onAdd = function() { this.div_ = document.createElement('DIV'); if (this.visible_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.cssText = this.createCss(pos); this.div_.innerHTML = this.sums_.text; } var panes = this.getPanes(); panes.overlayMouseTarget.appendChild(this.div_); var that = this; google.maps.event.addDomListener(this.div_, 'click', function(ev) { ev.preventDefault(); ev.stopPropagation(); that.triggerClusterClick(); }); }; /** * Returns the position to place the div dending on the latlng. * * @param {google.maps.LatLng} latlng The position in latlng. * @return {google.maps.Point} The position in pixels. * @private */ ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) { var pos = this.getProjection().fromLatLngToDivPixel(latlng); pos.x -= parseInt(this.width_ / 2, 10); pos.y -= parseInt(this.height_ / 2, 10); return pos; }; /** * Draw the icon. * @ignore */ ClusterIcon.prototype.draw = function() { if (this.visible_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.top = pos.y + 'px'; this.div_.style.left = pos.x + 'px'; } }; /** * Hide the icon. */ ClusterIcon.prototype.hide = function() { if (this.div_) { this.div_.style.display = 'none'; } this.visible_ = false; }; /** * Position and show the icon. */ ClusterIcon.prototype.show = function() { if (this.div_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.cssText = this.createCss(pos); this.div_.style.display = ''; } this.visible_ = true; }; /** * Remove the icon from the map */ ClusterIcon.prototype.remove = function() { this.setMap(null); }; /** * Implementation of the onRemove interface. * @ignore */ ClusterIcon.prototype.onRemove = function() { if (this.div_ && this.div_.parentNode) { this.hide(); this.div_.parentNode.removeChild(this.div_); this.div_ = null; } }; /** * Set the sums of the icon. * * @param {Object} sums The sums containing: * 'text': (string) The text to display in the icon. * 'index': (number) The style index of the icon. */ ClusterIcon.prototype.setSums = function(sums) { this.sums_ = sums; this.text_ = sums.text; this.index_ = sums.index; if (this.div_) { this.div_.innerHTML = sums.text; } this.useStyle(); }; /** * Sets the icon to the the styles. */ ClusterIcon.prototype.useStyle = function() { var index = Math.max(0, this.sums_.index - 1); index = Math.min(this.styles_.length - 1, index); var style = this.styles_[index]; this.url_ = style['url']; this.height_ = style['height']; this.width_ = style['width']; this.textColor_ = style['textColor']; this.anchor_ = style['anchor']; this.textSize_ = style['textSize']; this.backgroundPosition_ = style['backgroundPosition']; }; /** * Sets the center of the icon. * * @param {google.maps.LatLng} center The latlng to set as the center. */ ClusterIcon.prototype.setCenter = function(center) { this.center_ = center; }; /** * Create the css text based on the position of the icon. * * @param {google.maps.Point} pos The position. * @return {string} The css style text. */ ClusterIcon.prototype.createCss = function(pos) { var style = []; style.push('background-image:url(' + this.url_ + ');'); var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0'; style.push('background-position:' + backgroundPosition + ';'); if (typeof this.anchor_ === 'object') { if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 && this.anchor_[0] < this.height_) { style.push('height:' + (this.height_ - this.anchor_[0]) + 'px; padding-top:' + this.anchor_[0] + 'px;'); } else { style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + 'px;'); } if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 && this.anchor_[1] < this.width_) { style.push('width:' + (this.width_ - this.anchor_[1]) + 'px; padding-left:' + this.anchor_[1] + 'px;'); } else { style.push('width:' + this.width_ + 'px; text-align:center;'); } } else { style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;'); } var txtColor = this.textColor_ ? this.textColor_ : 'black'; var txtSize = this.textSize_ ? this.textSize_ : 11; style.push('cursor:pointer; top:' + pos.y + 'px; left:' + pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' + txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); return style.join(''); }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/RouteRenderer.js?ver=2.9.1 function CMMRM_RouteRenderer(widget, routeModel) { this.widget = widget; this.routeModel = routeModel; this.polylineCache = {}; this.polylines = []; this.polylineOutline = null; this.renderPolylines(); this.locationRenderers = this.renderLocations(); var that = this; jQuery(this.routeModel).bind('RouteModel:setTravelMode', function() { that.renderPolylines(); }); jQuery(this.routeModel).bind('RouteModel:setWaypointsString', function() { that.renderPolylines(); }); setTimeout(function() { that.widget.map.extendBounds(that.routeModel.getBounds()).center(); }, 500); jQuery(this).trigger('RouteRenderer:ready'); } CMMRM_RouteRenderer.prototype.renderLocations = function() { var locations = this.routeModel.getLocations(); var renderers = []; // var markers = []; for (var i=0; i https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/LocationModel.js?ver=2.9.1 function CMMRM_LocationModel(data, routeModel) { this.data = data; this.routeModel = routeModel; jQuery(this).trigger('LocationModel:ready'); } CMMRM_LocationModel.prototype.getId = function() { return this.data.id; }; CMMRM_LocationModel.prototype.getLat = function() { return this.data.lat; }; CMMRM_LocationModel.prototype.getLng = function() { return this.data.lng; }; CMMRM_LocationModel.prototype.getName = function() { return this.data.name; }; CMMRM_LocationModel.prototype.getPosition = function() { return [this.getLat(), this.getLng()]; }; CMMRM_LocationModel.prototype.getGoogleLatLng = function() { return new google.maps.LatLng(this.getLat(), this.getLng()); }; CMMRM_LocationModel.prototype.setPosition = function(lat, lng) { this.data.lat = lat; this.data.lng = lng; jQuery(this).trigger('LocationModel:setPosition', {lat: lat, lng: lng}); return this; }; CMMRM_LocationModel.prototype.remove = function() { jQuery(this).trigger('LocationModel:remove'); }; CMMRM_LocationModel.prototype.getRoute = function() { return this.routeModel; }; CMMRM_LocationModel.prototype.getIcon = function() { return this.data.icon; }; CMMRM_LocationModel.prototype.getIconSize = function() { return this.data.iconSize; }; CMMRM_LocationModel.prototype.getAddress = function() { return this.data.address; }; CMMRM_LocationModel.prototype.setAddress = function(address) { this.data.address = address; jQuery(this).trigger('LocationModel:setAddress', {address: address}); return this; }; CMMRM_LocationModel.prototype.getDescription = function() { return this.data.description; }; CMMRM_LocationModel.prototype.getImages = function() { if (typeof this.data.images == 'object') { return this.data.images; } else { return []; } }; CMMRM_LocationModel.prototype.getInfoWindowContent = function() { return this.data.infoWindowContent; }; CMMRM_LocationModel.prototype.getInfoWindowOpen = function() { return this.data.infoWindowOpen; }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/LocationRenderer.js?ver=2.9.1 function CMMRM_LocationRenderer(widget, locationModel) { this.widget = widget; this.locationModel = locationModel; this.marker = this.createMarker(); var that = this; jQuery(this.locationModel).bind('LocationModel:remove', function() { that.remove(); }); jQuery(this).trigger('LocationRenderer:ready'); } CMMRM_LocationRenderer.prototype.createMarker = function() { return new CMMRM_Marker(this.widget.map, this.locationModel.getGoogleLatLng(), this.getMarkerIconOptions(), this.getMarkerLabelOptions() ); }; CMMRM_LocationRenderer.prototype.getMarkerIconOptions = function() { return { draggable: false, style: 'cursor:pointer;', icon: this.locationModel.getIcon(), iconSize: this.locationModel.getIconSize(), color: this.widget.routeModel.getPathColor(), }; }; CMMRM_LocationRenderer.prototype.getMarkerLabelOptions = function() { return {text: this.getLabelText(), style: 'cursor:pointer;'}; }; CMMRM_LocationRenderer.prototype.getLabelText = function() { return this.locationModel.getName(); }; CMMRM_LocationRenderer.prototype.remove = function() { this.marker.setMap(null); }; CMMRM_LocationRenderer.prototype.getMarker = function() { return this.marker; }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/WaypointModel.js?ver=2.9.1 function CMMRM_WaypointModel(data, routeModel) { this.data = data; this.routeModel = routeModel; } CMMRM_WaypointModel.prototype.getLat = function() { return this.data[0]; }; CMMRM_WaypointModel.prototype.getLng = function() { return this.data[1]; }; CMMRM_WaypointModel.prototype.getPosition = function() { return [this.getLat(), this.getLng()]; }; CMMRM_WaypointModel.prototype.getGoogleLatLng = function() { return new google.maps.LatLng(this.getLat(), this.getLng()); }; CMMRM_WaypointModel.prototype.setPosition = function(lat, lng) { this.data[0] = lat; this.data[1] = lng; jQuery(this).trigger('WaypointModel:setPosition', {lat: lat, lng: lng}); return this; }; CMMRM_WaypointModel.prototype.remove = function() { jQuery(this).trigger('WaypointModel:remove'); }; CMMRM_WaypointModel.prototype.getRoute = function() { return this.routeModel; }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/WaypointRenderer.js?ver=2.9.1 function CMMRM_WaypointRenderer(widget, coords, index) { this.index = index; this.widget = widget; this.coords = coords; this.marker = this.createMarker(); var that = this; google.maps.event.addListener(this.marker, 'dragend', function() { var pos = that.marker.getPosition(); that.updatePosition(pos); // that.waypointModel.setPosition(pos.lat(), pos.lng()); }); google.maps.event.addListener(this.marker, 'click', function(ev) { that.remove(); }); // google.maps.event.addListener(this.marker, 'rightclick', function(ev) { // var pos = that.marker.getPosition(); // that.widget.addLocation(pos.lat(), pos.lng()); // that.waypointModel.remove(); // }); jQuery(this.waypointModel).bind('WaypointModel:remove', function() { that.remove(); that.widget.routeModel.updateWaypointsString(); that.widget.routeRenderer.renderPolylines(); }); // this.widget.routeRenderer.renderPolylines(); jQuery(this).trigger('WaypointRenderer:ready'); } CMMRM_WaypointRenderer.prototype.createMarker = function() { var markerImage = new google.maps.MarkerImage('https://maps.gstatic.com/mapfiles/dd-via.png', new google.maps.Size(11, 11), //size new google.maps.Point(0, 0), //origin point new google.maps.Point(6, 5)); // offset point var marker = new google.maps.Marker({ position: this.coords, map: this.widget.map.map, icon: markerImage, draggable: true, zIndex: 90000, }); marker.setZIndex(90000); return marker; }; CMMRM_WaypointRenderer.prototype.remove = function() { this.marker.setMap(null); jQuery(this).trigger('WaypointRenderer:remove'); }; CMMRM_WaypointRenderer.prototype.updatePosition = function(coords) { this.coords = coords; jQuery(this).trigger('WaypointRenderer:updatePosition', {coords: coords}); }; CMMRM_WaypointRenderer.prototype.getWaypointCoords = function() { return this.coords; }; CMMRM_WaypointRenderer.prototype.getWaypointIndex = function() { return this.index; }; CMMRM_WaypointRenderer.prototype.setWaypointIndex = function(index) { this.index = index; return this.index; }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/utils.js?ver=2.9.1 (function($) { window.CMMRM = {}; window.CMMRM.Utils = { addSingleHandler: function(handlerName, selector, action, func) { var obj; if (typeof selector == 'string') obj = $(selector); else obj = selector; obj.each(function() { var obj = $(this); if (obj.data(handlerName) != '1') { obj.data(handlerName, '1'); obj.on(action, func); } }); }, leftClick: function(func) { return function(e) { // Allow to use middle-button to open thread in a new tab: if (e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.ctrlKey) return; func.apply(this, [e]); return false; } }, toast: function(msg, className, duration) { if (typeof className != 'string') className = 'info'; if (typeof duration == 'undefined') duration = 5; var toast = $('
', {"class":"cmmrm-toast "+ className, "style":"display:none"}); toast.text(msg); $('body').append(toast); toast.fadeIn(500, function() { setTimeout(function() { toast.fadeOut(500); }, duration*1000); }); } }; $('.cmmrm-delete-confirm').click(function(ev) { if (!confirm(CMMRM_Utils.deleteConfirmText)) { ev.stopPropagation(); ev.preventDefault(); } }); })(jQuery); // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/Marker.js?ver=2.9.1 CMMRM_Marker.prototype = new google.maps.OverlayView(); function CMMRM_Marker(mapObj, position, markerOptions, labelOptions) { this.mapObj = mapObj; var map = mapObj.map; if (typeof markerOptions != 'object') markerOptions = {}; if (typeof markerOptions.color == 'undefined') markerOptions.color = '#ff6666'; if (typeof markerOptions.style == 'undefined') markerOptions.style = ''; if (typeof markerOptions.draggable == 'undefined') markerOptions.draggable = false; if (typeof markerOptions.icon != 'string') markerOptions.icon = ''; if (typeof markerOptions.title != 'string') markerOptions.title = ''; if (typeof labelOptions != 'object') labelOptions = {}; if (typeof labelOptions.style == 'undefined') labelOptions.style = ''; if (typeof labelOptions.text == 'undefined') labelOptions.text = ''; this.set('position', position); this._labelOptions = labelOptions; this._markerOptions = markerOptions; this.setMap(map); this._createContainer(); }; CMMRM_Marker.prototype._createContainer = function() { var that = this; var container = document.createElement('div'); google.maps.event.addDomListener(container, 'click', function(ev) { google.maps.event.trigger(that, 'click', ev); }); google.maps.event.addDomListener(container, 'mouseenter', function(ev) { google.maps.event.trigger(that, 'mouseenter', ev); }); google.maps.event.addDomListener(container, 'mouseleave', function(ev) { google.maps.event.trigger(that, 'mouseleave', ev); }); this.set('container', container); return container; }; /** * onAdd is called when the map's panes are ready and the overlay has been added * to the map. */ CMMRM_Marker.prototype.onAdd = function() { var container = this.getContainer(); container.style.position = 'absolute'; container.draggable = true; var markerHTML; if (this._markerOptions.icon.length > 0) { var iconUrl = this._markerOptions.icon; if (iconUrl.substr(0, 4) != 'http' && iconUrl.substr(0, 2) != '//') { iconUrl = 'https://maps.google.com/mapfiles/kml/shapes/' + iconUrl +'.png'; } var height = 40; var size = 'normal'; if (typeof this._markerOptions.iconSize == 'string' && this._markerOptions.iconSize.length > 0) { size = this._markerOptions.iconSize; } markerHTML = ''; } else { markerHTML = '
' + '
' + '
'; } container.innerHTML = '
'+ markerHTML +'
'; if (this._labelOptions.text.length > 0) { var labelLeft = 12 - this.getTextWidth( this._labelOptions.text, 10); container.innerHTML += '
' + this._labelOptions.text + '
'; } if (this._markerOptions.draggable) { this.setDragEvents(container); } // console.log(this._markerOptions); if (typeof this._markerOptions.title == 'string' && this._markerOptions.title.length > 0) { container.title = this._markerOptions.title; } // this.set('container', container) this.getPanes().floatPane.appendChild(container); }; CMMRM_Marker.prototype.getTextWidth = function(text, fontSize) { var narrow = '1tiIfjJl'; var wide = 'WODGKXZBM'; var result = 0; for (var i=0; i= 0 ? 1 : 0)) - (0.5*(narrow.indexOf(letter) >= 0 ? 1 : 0)); // console.log(letter +' : '+ rate); result += rate; } return result * fontSize*0.7/2; }; CMMRM_Marker.prototype.setDragEvents = function(container) { var dragging = false; var that = this; google.maps.event.addDomListener(this.get('map').getDiv(), 'mouseleave', function() { google.maps.event.trigger(container, 'mouseup'); }); google.maps.event .addDomListener( container, 'mousedown', function(e) { // console.log('mousedown'); that.mapObj.suspendAddWaypoints = true; dragging = true; this.style.cursor = 'move'; that.map.set('draggable', false); that.set('origin', e); that.moveHandler = google.maps.event .addDomListener( that.get('map').getDiv(), 'mousemove', function(e) { var origin = that.get('origin') var left = origin.clientX - e.clientX; var top = origin.clientY - e.clientY; var pos = that.getProjection().fromLatLngToDivPixel(that.get('position')); var latLng = that.getProjection().fromDivPixelToLatLng(new google.maps.Point(pos.x - left, pos.y - top)); that.set('origin', e); that.set('position', latLng); that.draw(); }); }); google.maps.event.addDomListener(container, 'mouseup', function(ev) { // console.log('mouseup'); if (ev) { if (ev.preventDefault) { ev.preventDefault(); } ev.cancelBubble = true; if (ev.stopPropagation) { ev.stopPropagation(); } } if (that.map) { that.map.set('draggable', true); } this.style.cursor = 'default'; google.maps.event.removeListener(that.moveHandler); google.maps.event.removeListener(that.clickHandler); if (dragging) { google.maps.event.trigger(that, 'dragend'); google.maps.event.trigger(that, 'positionUpdated'); } dragging = false; setTimeout(function() { that.mapObj.suspendAddWaypoints = false; }, 500); }); }; CMMRM_Marker.prototype.draw = function() { var pos = this.getProjection().fromLatLngToDivPixel(this.get('position')); this.get('container').style.left = (pos.x - 11) + 'px'; this.get('container').style.top = (pos.y - 30 - 12) + 'px'; return this; }; CMMRM_Marker.prototype.onRemove = function() { this.get('container').parentNode.removeChild(this.get('container')); this.set('container', null) }; CMMRM_Marker.prototype.getPosition = function() { return this.get('position'); }; CMMRM_Marker.prototype.setPosition = function(pos) { this.set('position', pos); this.draw(); google.maps.event.trigger(this, 'positionUpdated'); return this; }; CMMRM_Marker.prototype.getContainer = function() { var container = this.get('container'); if (!container) { container = this._createContainer(); } return container; }; // source --> https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/ElevationGraph.js?ver=2.9.1 function CMMRM_ElevationGraph(widget, routeModel) { this.widget = widget; this.routeModel = routeModel; this.results = null; this.maxElevation = 0; this.minElevation = 99999; this.elevationGain = 0; this.elevationDescent = 0; this.graph = null; this.graphData = null; if (this.routeModel.getTravelMode() == 'DIRECT') { this.calculateElevationAlongPath(this.routeModel.getWaypointsCoords()); this.initPolylineMouseEventListeners(); } var that = this; var timeout = null; jQuery(this.routeModel).bind('RouteModel:setPolylineString', function() { var route = this; clearTimeout(timeout); timeout = setTimeout(function() { that.calculateElevationAlongPath(route.getPolylineCoords()); }, 500); }); jQuery(widget.routeRenderer).bind('RouteRenderer:trailRequestSuccess', function() { that.initPolylineMouseEventListeners(); }); } CMMRM_ElevationGraph.prototype.calculateElevationAlongPath = function(path) { if (path.length < 2) return; var elevator = new google.maps.ElevationService; var that = this; // var dist = 0; // dist = this.widget.map.calculateDistance(path[0], path[path.length-1]); var samples = 450; //Math.min(450, Math.max(2, Math.floor(dist/5))); // console.log('dist = '+ dist + ' samples = '+ samples); path = this.reduceCoordsNumber(path, samples); elevator.getElevationAlongPath({ 'path': path, 'samples': samples, }, function(results, status) { // console.log(results); that.results = results; that.status = status; that.processElevationResults(results, status); }); }; CMMRM_ElevationGraph.prototype.reduceCoordsNumber = function(path, max) { // console.log('path.lengt = ', path.length); // console.log('max = ', max); if (path.length < max) return path; var result = []; var i = 0; var step = path.length/max; while (i < path.length) { result.push(path[Math.floor(i)]); i += step; } // console.log('result.len = ', result.length); return result; }; CMMRM_ElevationGraph.prototype.processElevationResults = function(results, status) { if (status !== google.maps.ElevationStatus.OK) { console.error('[CMMRM_ElevationGraph] Elevation service failed due to: ' + status); return; } this.maxElevation = 0; this.minElevation = 99999; this.elevationGain = 0; this.elevationDescent = 0; var prev = null; for (var i=0; i this.maxElevation) { this.maxElevation = elevation; } if (elevation < this.minElevation) { this.minElevation = elevation; } // console.log('elev '+ elevation +' --- '+(elevation-prev)); if (typeof prev == 'number') { if (elevation-prev > 0) { this.elevationGain += (elevation-prev); } else { this.elevationDescent += (prev-elevation); } } prev = elevation; } if (this.minElevation == 99999) { this.minElevation = 0; } this.showElevationGraph(results); jQuery(this).trigger('ElevationGraph:successResponse', {results: results}); }; CMMRM_ElevationGraph.prototype.showElevationGraph = function(elevations) { // console.log('showElevationGraph'); var graphDiv = this.getGraphCanvasContainer(); // console.log(this.widget); if (graphDiv.length == 0 || typeof google == 'undefined' || typeof google.visualization == 'undefined' || typeof google.visualization.ColumnChart == 'undefined') { console.error('[CMMRM_ElevationGraph] Missing library: google.visualization.ColumnChart'); return; } // this.showGoogleChart(elevations, graphDiv); this.showCustomChart(elevations, graphDiv); } CMMRM_ElevationGraph.prototype.showGoogleChart = function(elevations, graphDiv) { var graph = new google.visualization.ColumnChart(graphDiv[0]); this.graph = graph; var data = new google.visualization.DataTable(); this.graphData = data; var unit = ('feet' == CMMRM_Map_Settings.lengthUnits ? 'ft' : 'm'); // data.addColumn('number', 'Sample'); data.addColumn('number', 'Elevation'); for (var i = 0; i < elevations.length; i++) { var num = elevations[i].elevation / (unit == 'ft' ? CMMRM_Map_Settings.feetToMeter : 1); data.addRow([num]); } graph.draw(data, { height: 150, legend: 'none', titleY: 'Elevation ('+ unit +')', crosshair: null, }); var marker = new google.maps.Marker({ icon: 'https://maps.gstatic.com/mapfiles/dd-via.png', draggable: false, }); var googleMapObj = this.widget.map.map; google.visualization.events.addListener(graph, 'onmouseover', function(ev) { if (typeof elevations[ev.row] != 'undefined') { marker.setMap(googleMapObj); marker.setPosition(elevations[ev.row].location); } }); graphDiv.mouseout(function() { marker.setMap(null); }); }; CMMRM_ElevationGraph.prototype.showCustomChart = function(elevations, graphDiv) { var $ = jQuery; graphDiv.html(''); var container = $('
', {'class': 'cmmrm-custom-elevation-graph'}); graphDiv.append(container); // console.log(elevations); var max = null; var min = null; for (var i=0; i elevations[i].elevation) { min = elevations[i].elevation; } } // console.log(min, max); var divide = 1; var maxScale = 0; var minScale = 0; if (max-min < 10) { maxScale = Math.ceil(max) + 1; minScale = Math.floor(min) - 1; divide = 1; } else if (max-min < 100) { maxScale = Math.ceil(max/10)*10; minScale = Math.floor(min/10)*10; divide = 10; } else if (max-min < 500) { maxScale = Math.ceil(max/100)*100; minScale = Math.floor(min/100)*100; divide = 50; } else { maxScale = Math.ceil(max/100)*100; minScale = Math.floor(min/100)*100; divide = 100; } // console.log(minScale, maxScale, divide); var containerHeight = container.height(); var dividersCount = 1 + (maxScale-minScale)/divide; var dividerHeight = containerHeight/dividersCount; for (var i=0; i', {'class': 'cmmrm-divider'}); divider.text(minScale + divide*i); container.append(divider); divider.css('bottom', (dividerHeight*i) + 'px'); } var googleMapObj = this.widget.map.map; var marker = new google.maps.Marker({ icon: 'https://maps.gstatic.com/mapfiles/dd-via.png', draggable: false, }); var horizontalCursor = $('
', {'class': 'cmmrm-horizontal-cursor'}); container.append(horizontalCursor); var leftMargin = 30; var colWidth = (container.width() - leftMargin) / elevations.length; // console.log('colWidth', colWidth); for (var i=0; i', {'class': 'cmmrm-col'}); container.append(col); var h = (elevations[i].elevation - minScale) / (maxScale-minScale) * (containerHeight - dividerHeight); var left = (leftMargin + colWidth*i); // console.log(left, h); col.css('width', colWidth + 'px'); col.css('left', left + 'px'); col.css('height', h + 'px'); if (CMMRM_Map_Settings.elevationGraphColorAsPathColor == '1') { col.css('background', this.widget.routeModel.getPathColor()); } col.data('lat', elevations[i].location.lat()); col.data('long', elevations[i].location.lng()); col.mouseover(function() { var obj = $(this); marker.setMap(googleMapObj); marker.setPosition(new google.maps.LatLng(obj.data('lat'), obj.data('long'))); obj.addClass('current'); // horizontalCursor.css({width: (containerWidth - leftMargin) + 'px', bottom: 'px'}).show(); }); col.mouseout(function() { $(this).removeClass('current'); marker.setMap(null); }); } }; CMMRM_ElevationGraph.prototype.getGraphCanvasContainer = function() { return jQuery(this.widget.getWidgetElement()).find('.cmmrm-elevation-graph-canvas'); }; CMMRM_ElevationGraph.prototype.getGraphWrapper = function() { return jQuery(this.widget.getWidgetElement()).find('.cmmrm-elevation-graph'); }; CMMRM_ElevationGraph.prototype.removeElevationGraph = function() { this.getGraphCanvasContainer().html(''); }; CMMRM_ElevationGraph.prototype.getMaxElevation = function() { return this.maxElevation; }; CMMRM_ElevationGraph.prototype.getMinElevation = function() { return this.minElevation; }; CMMRM_ElevationGraph.prototype.getElevationGain = function() { return this.elevationGain; }; CMMRM_ElevationGraph.prototype.getElevationDescent = function() { return this.elevationDescent; }; CMMRM_ElevationGraph.prototype.initPolylineMouseEventListeners = function() { // @TODO maybe in future return; var renderer = this.widget.routeRenderer; var polylines = renderer.polylines; var that = this; for (var i=0; i https://etec.org.nz/wp-content/plugins/cm-maps-routes-manager-pro/asset/js/maps/Tooltip.js?ver=2.9.1 CMMRM_Tooltip.prototype = new google.maps.OverlayView(); function CMMRM_Tooltip(widget, position, content, style) { this.widget = widget; this.content = content; this.position = position; this.offsetTop = 0; this.offsetLeft = 0; if (typeof style != 'object') style = {}; this.style = style; // this.setMap(widget.map.map); } CMMRM_Tooltip.prototype.onAdd = function() { // console.log('CMMRM_Tooltip.prototype.onAdd'); var div = document.createElement('div'); div.setAttribute('class', 'cmmrm-map-tooltip'); div.style.borderStyle = 'solid'; div.style.borderColor = 'black'; div.style.borderWidth = '1px'; div.style.backgroundColor = '#ffff66'; div.style.padding = '0.2em 0.5em'; div.style.zIndex = '99999'; div.style.position = 'absolute'; for (var param in this.style) { div.style[param] = this.style[param]; } div.style.color = this.getContrastColor(div.style.backgroundColor); div.innerHTML = this.content; this.div_ = div; // Add the element to the "overlayLayer" pane. var panes = this.getPanes(); panes.overlayLayer.appendChild(div); }; CMMRM_Tooltip.prototype.draw = function() { // console.log('CMMRM_Tooltip.prototype.draw'); var pos = this.getProjection().fromLatLngToDivPixel(this.position); this.div_.style.left = (pos.x + this.offsetLeft) + 'px'; this.div_.style.top = (pos.y + this.offsetTop) + 'px'; return this; }; // The onRemove() method will be called automatically from the API if // we ever set the overlay's map property to 'null'. CMMRM_Tooltip.prototype.onRemove = function() { this.div_.parentNode.removeChild(this.div_); this.div_ = null; }; CMMRM_Tooltip.prototype.getContrastColor = function(color) { var d = 0; var hexToRgb = function(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { R: parseInt(result[1], 16), G: parseInt(result[2], 16), B: parseInt(result[3], 16) } : null; }; var componentToHex = function(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; }; var rgbToHex = function(r, g, b) { return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); } if (color.substr(0, 1) == '#') { color = hexToRgb(color); if (!color) { return '#000000'; } } else { // console.log(color); var result = color.match(/[0-9]+/g); if (result) { color = {R: result[0], G: result[1], B: result[2]}; } else { return '#000000'; } } // Counting the perceptive luminance - human eye favors green color... var a = 1 - ( 0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255; if (a < 0.5) d = 0; // bright colors - black font else d = 255; // dark colors - white font return rgbToHex(d, d, d); };